/* @Author: 邓威 ilovede@163.com
 * @Date: 2024-11-20 10:21:00
 * @LastEditors: 邓威
 * @LastEditTime: 2024-12-25 17:21:00
 * @Description: 重构逻辑,修复之前的漏洞,后续可扩展:1.提供选区api 2.将业务都放在fragment中处理提升性能 3.增加diff算法更新必要节点提升性能 4.增加清除所有格式api
 */
// 获取选中节点的函数
function getSelectNodes(range, commonAncestor, markerType) {
	const nodes = [];
	const treeWalker = document.createTreeWalker(commonAncestor, NodeFilter.SHOW_TEXT, {
		acceptNode: (node) => {
			if (range.intersectsNode(node) && node.textContent) {
				return NodeFilter.FILTER_ACCEPT;
			}
			return NodeFilter.FILTER_REJECT;
		},
	});

	// 特殊处理：起点和终点是同一个节点
	if (range.startContainer === range.endContainer && range.startContainer.nodeType === Node.TEXT_NODE) {
		nodes.push(range.startContainer);
		return nodes
	}

	let currentNode;
	while ((currentNode = treeWalker.nextNode())) {
		nodes.push(currentNode);
	}

	return nodes;
}

// 创建高亮节点的函数
function createMarkerNode(text, className) {
	const marker = document.createElement('marker');
	// 生成id
	marker.id = `marker-${Math.random().toString(36).substring(2, 9)}`;
	marker.className = className;
	marker.textContent = text;
	return marker;
}



// 合并相邻的高亮节点
function mergeMarkers(markerType, commonAncestor = document.querySelector('.content')) {
	// 创建 TreeWalker，遍历所有 <p> 元素节点
	const treeWalker = document.createTreeWalker(commonAncestor, NodeFilter.SHOW_ELEMENT, {
		acceptNode: (node) => {
			if (node.tagName === 'P' && node.querySelector(`marker.${markerType}`)) {
				return NodeFilter.FILTER_ACCEPT;
			}
			return NodeFilter.FILTER_REJECT;
		}
	});
	const paragraphs = [];
	let currentNode;
	while ((currentNode = treeWalker.nextNode())) {
		paragraphs.push(currentNode);
	}
	let hasMerged = false;
	paragraphs.forEach(paragraph => {
		let markers = Array.from(paragraph.querySelectorAll(`marker.${markerType}`));
		for (let i = 0; i < markers.length - 1; i++) {
			const currentMarker = markers[i];
			const nextMarker = markers[i + 1];
			// 获取当前 marker 的下一个兄弟节点，跳过空白文本节点
			let sibling = currentMarker.nextSibling;
			while (sibling && sibling.nodeType === Node.TEXT_NODE && !sibling.textContent.trim()) {
				sibling = sibling.nextSibling;
			}

			// 如果下一个兄弟节点是下一个 marker，则合并
			if (sibling === nextMarker) {
				// 合并文本内容
				currentMarker.textContent += nextMarker.textContent;

				// 移除下一个 marker 元素
				nextMarker.remove();

				// 标记已经进行了合并
				hasMerged = true;

				// 更新 markers 数组，减少索引偏移
				markers.splice(i + 1, 1);
				i--; // 调整索引以检查新的相邻关系
			}
		}
	});

	// 如果有进行合并，递归调用以确保所有相邻的 marker 都被合并
	if (hasMerged) {
		mergeMarkers(markerType, commonAncestor);
	}
}


// 选中逻辑
function MarkerSelection(markerType, params) {
	const selection = window.getSelection();
	if (selection.rangeCount === 0) {
		return;
	}

	const range = selection.getRangeAt(0);
	let startOffset = range.startOffset;
	let endOffset = range.endOffset;
	const startContainer = range.startContainer;
	const endContainer = range.endContainer;
	const commonAncestor = range.commonAncestorContainer;
	const nodes = getSelectNodes(range, commonAncestor, markerType);
	let newNodes = nodes.filter(node => !node.parentNode.classList.contains(markerType))
	console.log(newNodes)
	newNodes.forEach((node, index) => {
		//1.1 选区的开始节点落在marker上 startOffset =0
		if (startContainer.parentNode.classList.contains(markerType) && !endContainer.parentNode.classList.contains(markerType)) {
			console.log('%c选区的开始节点落在marker上', 'color:red')
			startOffset = 0;
			//如果选中的节点超过1个,只处理最后一个,其它的startOffset=0; endOffset=len
			// console.log(node)

			if (newNodes.length > 1 && index !== newNodes.length - 1) {
				let len = node.textContent.length;
				let text = node.textContent.slice(startOffset, len);
				let marker = createMarkerNode(text, markerType)
				range.setStart(node, startOffset)
				range.setEnd(node, len)
				range.deleteContents()
				range.insertNode(marker)
			} else {
				//最后一个
				let text = node.textContent.slice(startOffset, endOffset);
				let marker = createMarkerNode(text, markerType)
				range.setStart(node, startOffset)
				range.setEnd(node, endOffset)
				range.deleteContents()
				range.insertNode(marker)
			}
		} else if (endContainer.parentNode.classList.contains(markerType) && !startContainer.parentNode.classList.contains(markerType)) {
			//1.2 选区的结束节点落在marker上 endOffset = len
			console.log('%c选区的结束节点落在marker上', 'color:red')
			endOffset = node.textContent.length;
			if (newNodes.length > 1 && index !== 0) {
				let text = node.textContent.slice(0, endOffset);
				let marker = createMarkerNode(text, markerType)
				range.setStart(node, 0)
				range.setEnd(node, endOffset)
				range.deleteContents()
				range.insertNode(marker)
			} else {
				//第一个
				let text = node.textContent.slice(startOffset, endOffset);
				let marker = createMarkerNode(text, markerType)
				range.setStart(node, startOffset)
				range.setEnd(node, endOffset)
				range.deleteContents()
				range.insertNode(marker)
			}
		} else if (endContainer.parentNode.classList.contains(markerType) && startContainer.parentNode.classList.contains(markerType)) {
			//1.3 选区的开始节点和结束节点落在marker上 startOffset =0; endOffset=len
			console.log('%c选区的开始节点和结束节点落在marker上', 'color:red')
			startOffset = 0;
			endOffset = node.textContent.length;
			let text = node.textContent.slice(startOffset, endOffset);
			let marker = createMarkerNode(text, markerType)
			range.setStart(node, startOffset)
			range.setEnd(node, endOffset)
			range.deleteContents()
			range.insertNode(marker)
		} else if (!endContainer.parentNode.classList.contains(markerType) && !startContainer.parentNode.classList.contains(markerType)) {
			//1.4 选区的开始节点和结束节点都没有落在marker上
			if (newNodes.length > 1) {
				console.group('%c选区的开始节点和结束节点都没有落在marker上', 'color:red')
				//处理开头和结尾节点,其它高亮
				if (index === 0) {
					//开头节点
					console.log('%c开头节点', 'color:green')
					let len = node.textContent.length;
					let text = node.textContent.slice(startOffset, len);
					let marker = createMarkerNode(text, markerType)
					range.setStart(node, startOffset)
					range.setEnd(node, len)
					range.deleteContents()
					range.insertNode(marker)
				} else if (index === newNodes.length - 1) {
					//结尾节点
					console.log('%c结尾节点', 'color:green')
					let text = node.textContent.slice(0, endOffset);
					let marker = createMarkerNode(text, markerType)
					range.setStart(node, 0)
					range.setEnd(node, endOffset)
					range.deleteContents()
					range.insertNode(marker)
				} else {
					//中间节点
					console.log('%c中间节点', 'color:green')
					let len = node.textContent.length;
					let text = node.textContent.slice(0, len);
					let marker = createMarkerNode(text, markerType)
					range.setStart(node, 0)
					range.setEnd(node, len)
					range.deleteContents()
					range.insertNode(marker)
				}
				console.groupEnd('%c选区的开始节点和结束节点都没有落在marker上', 'color:red')
			} else {
				//第一个
				let text = node.textContent.slice(startOffset, endOffset);
				let marker = createMarkerNode(text, markerType)
				range.setStart(node, startOffset)
				range.setEnd(node, endOffset)
				range.deleteContents()
				range.insertNode(marker)
			}
		}
		setTimeout(() => {
			//合并marker,掩饰的目的是确保之前的高亮逻辑已经完成
			mergeMarkers(markerType)
		}, 50)
	})
}
// 清除高亮函数
function clearMarkers(markerType = 'marker') {
	let selection = window.getSelection();
	let range = selection.getRangeAt(0)
	// console.log(range.commonAncestorContainer)
	let nodes = getSelectNodes(range, range.commonAncestorContainer, markerType)
	// const Markers = container.querySelectorAll(`marker[class=markerType]`);
	console.log(nodes)
	nodes.forEach(node => {
		handleClearMarker(node, range, markerType)
	})
	selection.removeAllRanges();
}


let handleClearMarker = (node, range, markerType) => {
	//检查选中的节点是否是marker区域
	let isMarker = node.parentNode.classList.contains(markerType)
	let startContainer = range.startContainer.parentNode;
	let endContainer = range.endContainer.parentNode;
	if (isMarker) {
		let fragment = document.createDocumentFragment();
		//切割段落
		let textLength = node.textContent.length;
		let startOffset = range.startOffset;
		let endOffset = range.endOffset;
		let textContent = node.textContent;
		let fullTextLength = node.parentNode.parentNode.textContent.length;
		//如果选区左侧也偏移在marker外部,右侧也偏移在marker外部
		// console.log(node.parentNode)
		if (startContainer !== node.parentNode && endContainer !== node.parentNode) {
			// console.log('两端偏移')
			startOffset = 0;
			endOffset = node.textContent.length;
		} else if (startContainer !== node.parentNode) {
			// 如果选区偏移在当前marker外部左侧
			// console.log('左偏移')
			startOffset = 0;
		} else if (endContainer !== node.parentNode) {
			//如果选区偏移在当前marker外部右侧
			// console.log('右偏移')
			endOffset = node.length;
		}

		//清除选区在内容的结尾
		if (startOffset > 0 && endOffset == textLength) {
			let prevText = textContent.slice(0, startOffset);
			let lastText = textContent.slice(startOffset)
			let marker = createMarkerNode(prevText, markerType);
			let withoutMarkNode = document.createTextNode(lastText)
			fragment.appendChild(marker)
			fragment.appendChild(withoutMarkNode)
			console.log('判断1')
		} else if (startOffset === 0 && endOffset < textLength) {
			//清除选区在内容开头
			let prevText = textContent.slice(0, endOffset)
			let lastText = textContent.slice(endOffset, textLength)
			// console.log(prevText, 'prev', lastText, 'last')
			let marker = createMarkerNode(lastText, markerType)
			let withoutMarkNode = document.createTextNode(prevText)
			fragment.appendChild(withoutMarkNode)
			fragment.appendChild(marker)
			console.log('判断2')
		} else if (startOffset > 0 && endOffset < textLength) {
			//清除选区在内容中间
			let prevText = textContent.slice(0, startOffset)
			let middleText = textContent.slice(startOffset, endOffset)
			let lastText = textContent.slice(endOffset, textLength)
			// console.log(prevText, 'prev', lastText, 'last')
			let marker1 = createMarkerNode(prevText, markerType)
			let withoutMarkNode = document.createTextNode(middleText)
			let marker2 = createMarkerNode(lastText, markerType)
			fragment.appendChild(marker1)
			fragment.appendChild(withoutMarkNode)
			fragment.appendChild(marker2)
			console.log('判断3')
		} else if (textLength === endOffset || textLength == fullTextLength) {
			//清除整行选区
			let withoutMarkNode = document.createTextNode(textContent)
			fragment.appendChild(withoutMarkNode)
			console.log('else')
		}
		node.parentNode.parentNode.replaceChild(fragment, node.parentNode)

	}

}

// 高亮模块
const selectionTool = {
	execute: (command = 'mark', params = { color: 'yellow', markerType: null }) => {
		if (command === 'clearFormat') {
			let markerType = params.markerType ?? 'highlight';
			clearMarkers(markerType);
		} else {
			let markerType = params.markerType ?? command;
			MarkerSelection(markerType)
		}
	},
	getMarkers: (markerType) => {
		let markers = document.querySelectorAll(`marker[class='${markerType}']`);
		let results = [...markers].map(marker => {
			return {
				id: marker.id,
				text: marker.textContent,
				color: marker.style.backgroundColor
			}
		})
		return results
	},
	uninstall: () => {
		document.removeEventListener('mouseup', handler);
	}
};

export default selectionTool;
